/**
 * 编写优秀通用函数的准则
 * 1、可能的情况下，使用类型参数本身，而不是对其进行约束；
 * 2、总是尽可能少的使用类型参数；
 * 3、如果一个类型的参数只出现在一个地方，请重新考虑你是否真的需要它。
 * */
// 1
function firstElemnt1<Type>(arr: Type[]) {
  return arr[0]
}

function firstElemnt2<Type extends any[]>(arr: Type) {
  return arr[0]
}

const a_ele1 = firstElemnt1([1, 2, 3])
const b_ele2 = firstElemnt2([1, 2, 3])

// 2
function filter1<Type>(arr: Type[], func: (args: Type) => boolean) {
  return arr.filter(func)
}

function filter2<Type, Func extends (args: Type) => boolean>(
  arr: Type[],
  func: Func
) {
  return arr.filter(func)
}

// 3
function greet<Str extends string>(s: Str) {
  console.log('Hello' + s)
}

greet('World')

function greet2(s: string) {
  console.log('Hello' + s)
}